package com.cn.zengzeng.spbzengzeng.test;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.SSLContext;
import javax.validation.constraints.NotNull;
import java.io.IOException;
import java.lang.reflect.Field;
import java.net.URI;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.util.*;

/**
 * http客户端 工具类
 * @author zhangrong
 */
@Slf4j
public class HttpClientHelper {
    private static PoolingHttpClientConnectionManager poolingHttpClientConnectionManager;
    private static RequestConfig requestConfig;
    private final static String CHARSET = "UTF-8";

    private static void init() {
        if (poolingHttpClientConnectionManager == null) {
            poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager();
            poolingHttpClientConnectionManager.setMaxTotal(100);//整个连接池最大连接数
            poolingHttpClientConnectionManager.setDefaultMaxPerRoute(50);//单个路由默认最大连接数

            RequestConfig.Builder configBuilder = RequestConfig.custom();
            // 设置连接超时
            configBuilder.setConnectTimeout(5 * 1000);
            // 设置读取超时
            configBuilder.setSocketTimeout(8 * 1000);
            // 设置从连接池获取连接实例的超时
            configBuilder.setConnectionRequestTimeout(5 * 1000);
            requestConfig = configBuilder.build();
        }
    }

    /**
     * 通过连接池获取HttpClient
     *
     * @return
     */
    private static CloseableHttpClient getHttpClient(String accessUrl) {
        init();
        if (accessUrl.startsWith("https")) {
            return HttpClients.custom().setSSLSocketFactory(createSSLConnSocketFactory()).setConnectionManager(poolingHttpClientConnectionManager).setConnectionManagerShared(true).build();
        } else {
            return HttpClients.custom().setConnectionManager(poolingHttpClientConnectionManager).setConnectionManagerShared(true).build();
        }
    }

    /**
     * 创建SSL安全连接
     *
     * @return
     */
    private static SSLConnectionSocketFactory createSSLConnSocketFactory() {
        SSLConnectionSocketFactory sslsf = null;
        try {
            SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
                //信任所有
                @Override
                public boolean isTrusted(X509Certificate[] chain,String authType) {
                    return true;
                }
            }).build();
            sslsf = new SSLConnectionSocketFactory(sslContext);
        } catch (KeyManagementException e) {
            log.error("通用密钥管理异常", e);
        } catch (NoSuchAlgorithmException e) {
            log.error("加密算法不可用异常", e);
        } catch (KeyStoreException e) {
            log.error("SSL密钥已过时", e);

        }
        return sslsf;
    }

    /**
     * HTTP Get 获取内容
     *
     * @param apiUrl 请求的url地址 ?之前的地址
     * @param params 请求的参数
     */
    public static String doGet(@NotNull String apiUrl, Map<String, Object> params, Map<String, String> headerMap) {
        String responseResult = null;
        CloseableHttpResponse response = null;
        StringBuffer param = new StringBuffer();
        if (null != params && !params.isEmpty()) {
            for (String key : params.keySet()) {
                param.append(key).append("=").append(params.get(key)).append("&");
            }
            int i1 = param.lastIndexOf("&");
            param.deleteCharAt(i1);
            String str = apiUrl.contains("?") ? "&" : "?";
            param.insert(0, str);
            apiUrl += param;
        }
        HttpGet httpGet = new HttpGet();
        try (CloseableHttpClient closeableHttpClient = getHttpClient(apiUrl)) {
            httpGet.setURI(new URI(apiUrl));
            if (null != headerMap && !headerMap.isEmpty()) {
                headerMap.entrySet().forEach(entry -> {
                    httpGet.setHeader(entry.getKey(), entry.getValue());
                });
            }
            response = closeableHttpClient.execute(httpGet);
            HttpEntity entity = response.getEntity();
            responseResult = EntityUtils.toString(entity, CHARSET);
        } catch (Exception e) {
            httpGet.abort();
            log.error("io异常", e);
        } finally {
            if (response != null) {
                try {
                    EntityUtils.consume(response.getEntity());
                } catch (IOException e) {
                    log.error("关闭流异常", e);
                }
            }
        }
        return responseResult;
    }

    /**
     * json post请求
     * @param apiUrl      请求url
     * @param params      参数
     * @param headers     请求头参数
     * @return
     */
    public static String doPostJSON(String apiUrl,Object params,Map<String,String> headers){
//        String json = (String) JSONObject.toJSONString(params);
//        log.info("请求体:{}",json);
        return doPost(apiUrl, params,headers,ContentType.APPLICATION_JSON);
    }

    public static String doPUTJson(String apiUrl,Object params,Map<String,String> headers) throws IllegalAccessException {
        //return doPUT(apiUrl, JsonUtils.objectToMap(params),headers,ContentType.APPLICATION_JSON);
        return doPUT(apiUrl, objectToMap(params),headers,ContentType.APPLICATION_JSON);
    }

    /**
     * 普通form表单 post请求
     * @param apiUrl      请求url
     * @param params      参数
     * @param headers     请求头参数
     * @return
     */
    public static String doPostWWW_Form(String apiUrl,Map<String,Object> params,Map<String,String> headers){
        return doPost(apiUrl, params,headers,ContentType.APPLICATION_FORM_URLENCODED);
    }

    private static String doPost(String apiUrl, Object params, Map<String, String> headerMap, ContentType contentType) {
        String responseResult = null;
        HttpPost httpPost = new HttpPost();
        CloseableHttpResponse response = null;
        try (CloseableHttpClient closeableHttpClient = getHttpClient(apiUrl)) {
            httpPost.setURI(new URI(apiUrl));
            httpPost.setConfig(requestConfig);
            if (null != params) {
                if (contentType == ContentType.APPLICATION_JSON) {
                    httpPost.setEntity(new StringEntity((String) params, ContentType.APPLICATION_JSON));
                    httpPost.setHeader("Content-Type", ContentType.APPLICATION_JSON.getMimeType());
                } else {
                    Map<String,Object> paramsMap = (Map)params;
                    List<NameValuePair> pairList = new ArrayList<>(paramsMap.size());
                    for (Map.Entry<String, Object> entry : paramsMap.entrySet()) {
                        NameValuePair pair = new BasicNameValuePair(entry.getKey(), String.valueOf(entry.getValue()));
                        pairList.add(pair);
                    }
                    httpPost.setHeader("Content-Type", ContentType.APPLICATION_FORM_URLENCODED.getMimeType());
                    httpPost.setEntity(new UrlEncodedFormEntity(pairList, CHARSET));
                }
            }
            if (!Objects.isNull(headerMap) && !headerMap.isEmpty()) {
                headerMap.entrySet().forEach(entry -> {
                    httpPost.setHeader(entry.getKey(), entry.getValue());
                });
            }
            response = closeableHttpClient.execute(httpPost);
            HttpEntity entity = response.getEntity();
            responseResult = EntityUtils.toString(entity, CHARSET);
        } catch (Exception e) {
            throw new RuntimeException("网络IO操作异常",e);
        } finally {
            if (response != null) {
                try {
                    EntityUtils.consume(response.getEntity());
                } catch (IOException e) {
                    log.error("关闭流异常", e);
                }
            }
        }
        return responseResult;
    }

    private static String doPUT(String apiUrl, Map<String, Object> params, Map<String, String> headerMap, ContentType contentType) {
        String responseResult = null;
        HttpPut httpPut = new HttpPut();
        CloseableHttpResponse response = null;
        try (CloseableHttpClient closeableHttpClient = getHttpClient(apiUrl)) {
            httpPut.setURI(new URI(apiUrl));
            httpPut.setConfig(requestConfig);
            if (null != params && !params.isEmpty()) {
                if (contentType == ContentType.APPLICATION_JSON) {
                    String json =JSON.toJSONString(params);
                    log.info("请求体:{}",json);
                    httpPut.setEntity(new StringEntity(json, ContentType.APPLICATION_JSON));
                    httpPut.setHeader("Content-Type", ContentType.APPLICATION_JSON.getMimeType());
                } else {
                    List<NameValuePair> pairList = new ArrayList<>(params.size());
                    for (Map.Entry<String, Object> entry : params.entrySet()) {
                        NameValuePair pair = new BasicNameValuePair(entry.getKey(), String.valueOf(entry.getValue()));
                        pairList.add(pair);
                    }
                    httpPut.setEntity(new UrlEncodedFormEntity(pairList, CHARSET));
                }
            }
            if (!Objects.isNull(headerMap) && !headerMap.isEmpty()) {
                headerMap.entrySet().forEach(entry -> {
                    httpPut.setHeader(entry.getKey(), entry.getValue());
                });
            }
            response = closeableHttpClient.execute(httpPut);
            HttpEntity entity = response.getEntity();
            responseResult = EntityUtils.toString(entity, CHARSET);
        } catch (Exception e) {
            throw new RuntimeException("网络IO操作异常",e);
        } finally {
            if (response != null) {
                try {
                    EntityUtils.consume(response.getEntity());
                } catch (IOException e) {
                    log.error("关闭流异常", e);
                }
            }
        }
        return responseResult;
    }

    public static Map<String, Object> objectToMap(Object obj) throws IllegalAccessException {
        Map<String, Object> map = new HashMap<>();
        Class<?> clazz = obj.getClass();
        System.out.println(clazz);
        for (Field field : clazz.getDeclaredFields()) {
            field.setAccessible(true);
            String fieldName = field.getName();
            Object value = field.get(obj);
            map.put(fieldName, value);
        }
        return map;
    }

}
